/**
 * 
 */
package br.elite.dao;

import java.util.List;

import javax.persistence.PersistenceException;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 * @author antonio 05-04-2011
 *
 */
public class GenericDAO {
	
	/**
	 * M&eacute;todo que informada uma classe e sua propriedade id a ser imcrementada,<br/>
	 * consulta o maior id e retona ele mais 1.<br/>
	 * id+1
	 * 
	 * @param classe
	 * @param id
	 * @return
	 * @throws PersistenceException
	 */
	public Long proximoId(String classe, String id) throws PersistenceException {
		try {
			getSession().beginTransaction();

			StringBuilder hql = new StringBuilder();

			hql.append("select max(g.").append(id).append(")");
			hql.append(" from ").append(classe).append(" g ");

			Query q  = getSession().createQuery(hql.toString());

			Number n = (Number) q.uniqueResult();

			Long maxId = (n == null ? 0 : n.longValue());
			maxId++;
			return maxId;
		} catch (Exception e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		}
	}
	
	/**
	 * M&eacute;todo que busca todos os objetos da classe informada.
	 * 
	 * @param classe
	 * @return
	 * @throws PersistenceException
	 */
	@SuppressWarnings("unchecked")
	public List<Object> buscarTodos(String classe, String ordenarPor, String tipoOrdenacao) throws PersistenceException {
		try {
			getSession().beginTransaction();
			StringBuilder hql = new StringBuilder();
			hql.append(" from ").append(classe);
			
			if (ordenarPor != null && !"".equals(ordenarPor.trim()) && tipoOrdenacao != null && !"".equals(tipoOrdenacao.trim()) ) {
				hql.append(" order by ").append(ordenarPor).append(" ").append(tipoOrdenacao);
			} else {
				hql.append(" order by ").append(ordenarPor).append(" asc");
			}
			
			Query query = getSession().createQuery(hql.toString());
			
			return query.list();
		} catch (Exception e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		} finally {
			getSession().clear();
		}
	}
	
	/**
	 * M&eacute;todo que persiste o objeto informado.
	 * 
	 * @param obj
	 */
	public void salva(Object obj) {
		try {
			Transaction tx = getSession().beginTransaction();
			getSession().save(obj);
			getSession().flush();
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		}
	}
	/**
	 * M&eacute;todo que persiste o objeto informado.
	 * 
	 * @param obj
	 */
	public void atualiza(Object obj) {
		try {
			Transaction tx = getSession().beginTransaction();
			getSession().update(obj);
			getSession().flush();
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		}
	}
	
	/**
	 * Metodo que salva ou atualiza um objeto.
	 * 
	 * @param obj
	 */
	public void salvarOuAtualizar(Object obj) {
		try {
			Transaction tx = getSession().beginTransaction();
			getSession().saveOrUpdate(obj);
			getSession().flush();
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		}
	}
	
	/**
	 * M&eacute;todo que valida se j&aacute; existe um objeto persistido com a descri&ccedil;&atilde;o informada.
	 * 
	 * @param classe
	 * @param propriedade
	 * @param descricao
	 * @return
	 */
	public boolean validarDescriacaoJaPersistida(String classe, String propriedade, String descricao, int estrutura){
		try {
			getSession().beginTransaction();
			StringBuilder hql = new StringBuilder(" select count(*) ");
			hql.append(" from ").append(classe).append(" g ");
			hql.append(" where g.").append(propriedade);
			hql.append(" = '").append(descricao).append("'");
			hql.append(" g.estrutura = ").append(estrutura);
			Query query = getSession().createQuery(hql.toString());
			Number result = (Number) query.uniqueResult(); 
			return (result.intValue() == 0 ? false : true);
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		}
	}
	
	/**
	 * M&eacute;todo que exclui o objeto informado.
	 * 
	 * @param obj
	 */
	public void excluir(Object obj) {
		try {
			Transaction tx = getSession().beginTransaction();
			getSession().delete(obj);
			getSession().flush();
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		}
	}
	
	/**
	 * @param id
	 * @param propriedadeId
	 * @param classe
	 * @return
	 */
	public Object buscarPorId(Long id, String propriedadeId, String classe) {
		try {
			getSession().beginTransaction();

			StringBuilder hql = new StringBuilder();

			hql.append(" from ").append(classe).append(" g ");
			hql.append(" where g.").append(propriedadeId).append(" = ").append(id);
			
			Query q = getSession().createQuery(hql.toString());
			return q.uniqueResult();
			
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new PersistenceException(e);
		} finally{
			getSession().clear();
		}
	}
	
	public Session getSession() {
		return	SessionFactoryUtil.getInstance().getCurrentSession();
	}

}
